﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Jy.Abp.Settings;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SettingManagement;

namespace Jy.Abp.TypedSettings;

public class TypedSettingsManager : ITypedSettingsManager, ITransientDependency
{
    private readonly ISettingManager _settingManager;
    private readonly ITypedSettingsInitialization _typedSettingsInitialization;

    public TypedSettingsManager(
        ISettingManager settingManager,
        ITypedSettingsInitialization typedSettingsInitialization)
    {
        _settingManager = settingManager;
        _typedSettingsInitialization = typedSettingsInitialization;
    }

    public async Task SetForUserAsync<TSettings>(Guid userId, TSettings settings)
        where TSettings : ITypedSettings
    {
        await SetAsync(settings, userId: userId);
    }

    public async Task SetForTenantAsync<TSettings>(Guid tenantId, TSettings settings)
       where TSettings : ITypedSettings
    {
        await SetAsync(settings, tenantId: tenantId);
    }

    public async Task SetGlobalAsync<TSettings>(TSettings settings)
        where TSettings : ITypedSettings
    {
        var type = typeof(TSettings);
        var curr = _typedSettingsInitialization.Settings.GetOrDefault(type);
        Check.NotNull(curr, nameof(settings));
        foreach (var p in type.GetProperties())
        {
            var val = p.GetValue(settings);
            //更新实际配置
            var settingName = TypedSettingsHelper.CreateSettingName(p);
            await _settingManager.SetGlobalAsync(settingName, val?.ToString());

            //更新当前
            p.SetValue(curr, val);
        }
    }

    protected virtual async Task SetAsync<TSettings>(
        TSettings settings,
        bool forceToSet = false,
        Guid? userId = null,
        Guid? tenantId = null)
       where TSettings : ITypedSettings
    {
        var type = typeof(TSettings);
        var curr = _typedSettingsInitialization.Settings.GetOrDefault(type);
        Check.NotNull(curr, nameof(settings));
        foreach (var p in type.GetProperties())
        {
            var val = p.GetValue(settings);
            //更新实际配置
            var settingName = TypedSettingsHelper.CreateSettingName(p);
            if (userId.HasValue)
                await _settingManager.SetForUserAsync(userId.Value, settingName, val?.ToString(), forceToSet);
            else if (tenantId.HasValue)
                await _settingManager.SetForTenantAsync(tenantId.Value, settingName, val?.ToString(), forceToSet);
            else
                await _settingManager.SetGlobalAsync(settingName, val?.ToString());

            //更新当前
            p.SetValue(curr, val);
        }
    }

    public async Task<TSettings> GetAsync<TSettings>()
        where TSettings : class, ITypedSettings
    {
        var type = typeof(TSettings);
        if (!this._typedSettingsInitialization.Settings.ContainsKey(type))
            throw new ArgumentException($"{type.Name} not found.");
        var settings = this._typedSettingsInitialization
                           .Settings[type]
                           .As<TSettings>();

        return await Task.FromResult(settings);
    }
}
